﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Text.Json;
using Microsoft.Extensions.Logging;

namespace Kingzad.MicroService.BusinessCore.Providers
{
    public interface IHttpClientProvider
    {
        Task<T> GetSingleDataAsync<T>(string httpClientName, Uri url, string accessToken);
        Task<IEnumerable<T>> GetDataAsync<T>(string httpClientName, Uri url, string accessToken);
        Task<T> PostSingleDataAsync<T>(string httpClientName, Uri url, string accessToken, StringContent content);
        Task<IEnumerable<T>> PostDataAsync<T>(string httpClientName, Uri url, string accessToken, StringContent content);
        Task<T> PutSingleDataAsync<T>(string httpClientName, Uri url, string accessToken, StringContent content);
        Task<IEnumerable<T>> PutDataAsync<T>(string httpClientName, Uri url, string accessToken, StringContent content);
        Task DeleteDataAsync(string httpClientName, Uri url, string accessToken);
    }

    public class HttpClientProvider : IHttpClientProvider
    {
        private readonly IHttpClientFactory _clientFactory;
        private readonly ILogger<IHttpClientProvider> _logger;

        public HttpClientProvider(IHttpClientFactory clientFactory, ILogger<IHttpClientProvider> logger)
        {
            _clientFactory = clientFactory;
            _logger = logger;
        }

        public async Task<T> GetSingleDataAsync<T>(string httpClientName, Uri url, string accessToken)
        {
            try
            {
                using (var client = _clientFactory.CreateClient(httpClientName))
                {
                    if (client.BaseAddress?.Scheme == "https")
                    {
                        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
                        ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
                    }

                    if (!string.IsNullOrEmpty(accessToken))
                        client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", accessToken);

                    var response = await client.GetAsync(url).ConfigureAwait(false);
                    response.EnsureSuccessStatusCode();

                    string body = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
                    if (string.IsNullOrEmpty(body))
                        return default;

                    return JsonSerializer.Deserialize<T>(body);
                }
            }
            catch (Exception e)
            {
                _logger.LogError(e, "PostData", url, e.Message);
                return default;
            }
        }

        public async Task<IEnumerable<T>> GetDataAsync<T>(string httpClientName, Uri url, string accessToken)
        {
            try
            {
                using (var client = _clientFactory.CreateClient(httpClientName))
                {
                    if (client.BaseAddress?.Scheme == "https")
                    {
                        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
                        ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
                    }

                    if (!string.IsNullOrEmpty(accessToken))
                        client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", accessToken);

                    var response = await client.GetAsync(url).ConfigureAwait(false);
                    response.EnsureSuccessStatusCode();

                    string body = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
                    if (string.IsNullOrEmpty(body))
                        return default;

                    return JsonSerializer.Deserialize<IEnumerable<T>>(body);
                }
            }
            catch (Exception e)
            {
                _logger.LogError(e, "PostData", url, e.Message);
                return default;
            }
        }

        public async Task<T> PostSingleDataAsync<T>(string httpClientName, Uri url, string accessToken, StringContent content)
        {
            try
            {
                using (var client = _clientFactory.CreateClient(httpClientName))
                {
                    if (client.BaseAddress?.Scheme == "https")
                    {
                        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
                        ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
                    }

                    if (!string.IsNullOrEmpty(accessToken))
                        client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", accessToken);

                    var response = await client.PostAsync(url, content).ConfigureAwait(false);
                    response.EnsureSuccessStatusCode();

                    string body = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
                    if (string.IsNullOrEmpty(body))
                        return default;

                    return JsonSerializer.Deserialize<T>(body);
                }
            }
            catch (Exception e)
            {
                _logger.LogError(e, "PostData", url, e.Message);
                return default;
            }
        }

        public async Task<IEnumerable<T>> PostDataAsync<T>(string httpClientName, Uri url, string accessToken, StringContent content)
        {
            try
            {
                using (var client = _clientFactory.CreateClient(httpClientName))
                {
                    if (client.BaseAddress?.Scheme == "https")
                    {
                        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
                        ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
                    }

                    if (!string.IsNullOrEmpty(accessToken))
                        client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", accessToken);

                    var response = await client.PostAsync(url, content).ConfigureAwait(false);
                    response.EnsureSuccessStatusCode();

                    string body = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
                    if (string.IsNullOrEmpty(body))
                        return default;

                    return JsonSerializer.Deserialize<IEnumerable<T>>(body);
                }
            }
            catch (Exception e)
            {
                _logger.LogError(e, "PostData", url, e.Message);
                return default;
            }
        }

        public async Task<T> PutSingleDataAsync<T>(string httpClientName, Uri url, string accessToken, StringContent content)
        {
            try
            {
                using (var client = _clientFactory.CreateClient(httpClientName))
                {
                    if (client.BaseAddress?.Scheme == "https")
                    {
                        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
                        ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
                    }

                    if (!string.IsNullOrEmpty(accessToken))
                        client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", accessToken);

                    var response = await client.PutAsync(url, content).ConfigureAwait(false);
                    response.EnsureSuccessStatusCode();

                    string body = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
                    if (string.IsNullOrEmpty(body))
                        return default;

                    return JsonSerializer.Deserialize<T>(body);
                }
            }
            catch (Exception e)
            {
                _logger.LogError(e, "PostData", url, e.Message);
                return default;
            }
        }

        public async Task<IEnumerable<T>> PutDataAsync<T>(string httpClientName, Uri url, string accessToken, StringContent content)
        {
            try
            {
                using (var client = _clientFactory.CreateClient(httpClientName))
                {
                    if (client.BaseAddress?.Scheme == "https")
                    {
                        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
                        ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
                    }

                    if (!string.IsNullOrEmpty(accessToken))
                        client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", accessToken);

                    var response = await client.PutAsync(url, content).ConfigureAwait(false);
                    response.EnsureSuccessStatusCode();

                    string body = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
                    if (string.IsNullOrEmpty(body))
                        return default;

                    return JsonSerializer.Deserialize<IEnumerable<T>>(body);
                }
            }
            catch (Exception e)
            {
                _logger.LogError(e, "PostData", url, e.Message);
                return default;
            }
        }
        
        public async Task DeleteDataAsync(string httpClientName, Uri url, string accessToken)
        {
            try
            {
                using (var client = _clientFactory.CreateClient(httpClientName))
                { 

                    if (!string.IsNullOrEmpty(accessToken))
                        client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", accessToken);

                    var response = await client.DeleteAsync(url).ConfigureAwait(false);
                    response.EnsureSuccessStatusCode();
                }
            }
            catch (Exception e)
            {
                _logger.LogError(e, "PostData", url, e.Message);
            }
        }
    }
}
